﻿namespace Launcher
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Configuration;
    using System.Windows.Forms;
    using System.Reflection;
    using System.IO;
    using Gunningine;

    /// <summary>
    /// Entry point.
    /// 
    /// We scan through the DLLs in the same directory, and see if they are game DLLs.
    /// If we find just one, then load that, otherwise prompt for the one to load.
    /// 
    /// We then create an instance of a GameState which has the InitialStateAttribute.
    /// which marks it as the initial state.  If none or multiple states have this,
    /// then exit with failure.
    /// </summary>
    class Program
    {
        /// <summary>
        /// Frequency of logic updates, in Hz
        /// </summary>
        private const double UPDATE_FREQUENCY = 60.0;

        /// <summary>
        /// Main.
        /// </summary>
        /// <param name="args">command line arguments.</param>
        static void Main(string[] args)
        {
            try
            {
                // Load plugins and rendersystems.
                string[] pluginFiles = Directory.GetFiles(@".\Plugins", "*.dll", SearchOption.TopDirectoryOnly);
                List<Type> pluginTypes = new List<Type>();
                List<Type> renderSystemTypes = new List<Type>();
                foreach (string plugin in pluginFiles)
                {
                    Assembly pluginAsm = Assembly.LoadFrom(plugin);
                    var plugins = pluginAsm.GetTypes().Where(t => typeof(IResourceLoader).IsAssignableFrom(t));
                    pluginTypes.AddRange(plugins.ToList());

                    var renderSystems = pluginAsm.GetTypes().Where(t => typeof(RenderSystem).IsAssignableFrom(t));
                    renderSystemTypes.AddRange(renderSystems);
                }

                if (renderSystemTypes.Count == 0)
                    throw new Exception("Could not find any render systems 'Plugins' directory!");
                else if (renderSystemTypes.Count > 1)
                    throw new Exception("Found multiple render systems in 'Plugins' directory!  In future, you will be able to choose.");

                // Read in default settings.
                string resourceLoc = ConfigurationManager.AppSettings["ResourceLocation"];
                string windowTitle = ConfigurationManager.AppSettings["WindowTitle"];
                int windowWidth = Int32.Parse(ConfigurationManager.AppSettings["DefaultScreenWidth"]);
                int windowHeight = Int32.Parse(ConfigurationManager.AppSettings["DefaultScreenHeight"]);
                bool fullScreen = Boolean.Parse(ConfigurationManager.AppSettings["DefaultFullScreen"]);
                bool useVSync =  Boolean.Parse(ConfigurationManager.AppSettings["DefaultUseVSync"]);

                // Create the root facade.
                Root root = new Root(
                    resourceLoc,
                    pluginTypes.Select(p => (IResourceLoader)Activator.CreateInstance(p)).ToList(),
                    renderSystemTypes.First(),
                    windowTitle,
                    windowWidth,
                    windowHeight,
                    fullScreen,
                    useVSync);

                root.Run(UPDATE_FREQUENCY, UPDATE_FREQUENCY);
            }
            catch (Exception e)
            {
                Logger.Fatal(e.Message);
                
                MessageBox.Show(e.Message, 
                                ConfigurationManager.AppSettings["WindowTitle"], 
                                MessageBoxButtons.OK, 
                                MessageBoxIcon.Error);

                Environment.ExitCode = 1;
            }
        }
    }
}
